/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.openatom.ubml.model.be.definition;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.openatom.ubml.model.be.definition.beenum.BETriggerTimePointType;
import org.openatom.ubml.model.be.definition.common.OperationConvertUtils;
import org.openatom.ubml.model.be.definition.json.object.BizObjectDeserializer;
import org.openatom.ubml.model.be.definition.json.object.BizObjectSerializer;
import org.openatom.ubml.model.be.definition.operation.collection.BizActionCollection;
import org.openatom.ubml.model.be.definition.operation.collection.DeterminationCollection;
import org.openatom.ubml.model.be.definition.operation.collection.ValidationCollection;
import org.openatom.ubml.model.be.definition.operation.internalbeaction.DeleteBEAction;
import org.openatom.ubml.model.be.definition.operation.internalbeaction.ModifyBEAction;
import org.openatom.ubml.model.be.definition.operation.internalbeaction.RetrieveBEAction;
import org.openatom.ubml.model.common.definition.cef.IGspCommonField;
import org.openatom.ubml.model.common.definition.cef.collection.CommonDtmCollection;
import org.openatom.ubml.model.common.definition.cef.collection.CommonValCollection;
import org.openatom.ubml.model.common.definition.cef.element.GspAssociationKey;
import org.openatom.ubml.model.common.definition.cef.element.GspElementDataType;
import org.openatom.ubml.model.common.definition.cef.element.GspElementObjectType;
import org.openatom.ubml.model.common.definition.cef.util.Guid;
import org.openatom.ubml.model.common.definition.commonmodel.IGspCommonElement;
import org.openatom.ubml.model.common.definition.commonmodel.IGspCommonObject;
import org.openatom.ubml.model.common.definition.commonmodel.collection.GspElementCollection;
import org.openatom.ubml.model.common.definition.commonmodel.collection.GspObjectCollection;
import org.openatom.ubml.model.common.definition.commonmodel.entity.GspCommonObject;
import org.openatom.ubml.model.common.definition.commonmodel.entity.element.GspCommonAssociation;
import org.openatom.ubml.model.common.definition.commonmodel.entity.object.GspColumnGenerate;
import org.openatom.ubml.model.common.definition.commonmodel.entity.object.GspCommonObjectType;

/**
 * The Definition Of Be Entity Object
 *
 * @ClassName: GspBizEntityObject
 * @Author: Benjamin Gong
 * @Date: 2021/1/11 17:13
 * @Version: V1.0
 */
@JsonDeserialize(using = BizObjectDeserializer.class)
@JsonSerialize(using = BizObjectSerializer.class)
public class GspBizEntityObject extends GspCommonObject implements Cloneable {

    // 私有属性
    private DeterminationCollection determinations;
    private ValidationCollection validations;
    private BizActionCollection bizActions;

    private LogicDeleteControlInfo logicDeleteControlInfo;

    public GspBizEntityObject() {
        super();
    }

    public final boolean getIsRootNode() {
        return getParentObject() == null;
    }

    public LogicDeleteControlInfo getLogicDeleteControlInfo() {
        return logicDeleteControlInfo;
    }

    public void setLogicDeleteControlInfo(LogicDeleteControlInfo logicDeleteControlInfo) {
        this.logicDeleteControlInfo = logicDeleteControlInfo;
    }

    /**
     * 当前节点的操作集合
     * <p>
     * //public BizOperationCollection Operations //{ // get { return operations ??
     * (operations = new BizOperationCollection()); // internal set { return
     * operations = value; //}
     */

    public final DeterminationCollection getDeterminations() {
        if (determinations == null) {
            determinations = new DeterminationCollection();

        }
        determinations.setOwner(this);
        return determinations;
    }

    public final void setDeterminations(DeterminationCollection value) {
        determinations = value;
        if (determinations != null) {
            determinations.setOwner(this);
        }
    }

    public final ValidationCollection getValidations() {
        if (validations == null) {
            validations = new ValidationCollection();

        }
        validations.setOwner(this);
        return validations;
    }

    public final void setValidations(ValidationCollection value) {
        validations = value;
        validations.setOwner(this);
    }

    public final BizActionCollection getBizActions() {
        if (bizActions == null) {
            bizActions = new BizActionCollection();

        }
        bizActions.setOwner(this);
        return bizActions;
    }

    public final void setBizActions(BizActionCollection value) {
        bizActions = value;
        bizActions.setOwner(this);
    }

    /**
     * 当前节点的所属模型
     */
    public final GspBusinessEntity getBelongModel() {
        return (GspBusinessEntity)super.getBelongModel();
    }

    /**
     * 父节点
     */
    public final GspBizEntityObject getParentObject() {
        return (GspBizEntityObject)((super.getParentObject() instanceof GspBizEntityObject) ? super.getParentObject()
                : null);
    }

    public final void setParentObject(GspBizEntityObject value) {
        super.setParentObject(value);
    }

    /**
     * [保存前]联动计算
     */
    @Override
    public CommonDtmCollection getDtmBeforeSave() {
        return OperationConvertUtils.convertToCommonDtms(getDeterminations(), BETriggerTimePointType.BeforeCheck);
    }

    @Override
    public void setDtmBeforeSave(CommonDtmCollection value) {
//        throw new RuntimeException("业务实体中无法赋值属性[DtmBeforeSave]");
    }

    /**
     * [更新后]联动计算
     */
    @Override
    public CommonDtmCollection getDtmAfterModify() {
        return OperationConvertUtils.convertToCommonDtms(getDeterminations(), BETriggerTimePointType.AfterModify);
    }

    @Override
    public void setDtmAfterModify(CommonDtmCollection value) {
//        throw new RuntimeException("业务实体中无法赋值属性[DtmAfterModify]");
    }

    /**
     * [新增后]联动计算
     */
    @Override
    public CommonDtmCollection getDtmAfterCreate() {
        return OperationConvertUtils.convertToCommonDtms(getDeterminations(), BETriggerTimePointType.RetrieveDefault);
    }

    @Override
    public void setDtmAfterCreate(CommonDtmCollection value) {
//        throw new RuntimeException("业务实体中无法赋值属性[DtmAfterCreate]");
    }

    /**
     * [查询前]联动计算, 用来自定义过滤条件
     */
    public CommonDtmCollection getDtmBeforeQuery() {
        return OperationConvertUtils.convertToCommonDtms(getDeterminations(), BETriggerTimePointType.BeforeQuery);
    }

    public void setDtmBeforeQuery(CommonDtmCollection value) {
//        throw new RuntimeException("业务实体中无法赋值属性[DtmBeforeQuery]");
    }

    /**
     * [查询前]联动计算, 用来自定义过滤条件
     */
    public CommonDtmCollection getDtmBeforeRetrieve() {
        return OperationConvertUtils.convertToCommonDtms(getDeterminations(), BETriggerTimePointType.BeforeRetrieve);
    }

    /**
     * [保存前]校验规则
     */
    @Override
    public CommonValCollection getValBeforeSave() {
        return OperationConvertUtils.convertToCommonValidations(getValidations(), BETriggerTimePointType.BeforeCheck);
    }

    @Override
    public void setValBeforeSave(CommonValCollection value) {
//        throw new RuntimeException("业务实体中无法赋值属性[ValBeforeSave]");
    }

    /**
     * [保存后]校验规则
     */
    public CommonValCollection getValAfterSave() {
        return OperationConvertUtils.convertToCommonValidations(getValidations(), BETriggerTimePointType.AfterSave);
    }

    /**
     * [更新后]校验规则，20181017更新不需要override
     */
    @Override
    public CommonValCollection getValAfterModify() {
        return OperationConvertUtils.convertToCommonValidations(getValidations(), BETriggerTimePointType.AfterModify);
    }

    @Override
    public void setValAfterModify(CommonValCollection value) {
//        throw new RuntimeException("业务实体中无法赋值属性[ValAfterModify]");
    }

    /**
     * 克隆
     *
     * @return
     */
    @Override
    public GspBizEntityObject clone() {
        GspCommonObject tempVar = super.clone();
        GspBizEntityObject node = (GspBizEntityObject)((tempVar instanceof GspBizEntityObject) ? tempVar : null);
        if (node == null) {
            return null;
        }
        if (getDeterminations() != null) {
            DeterminationCollection tempVar2 = getDeterminations().clone();
            node.setDeterminations(
                    (DeterminationCollection)((tempVar2 instanceof DeterminationCollection) ? tempVar2 : null));
        }
        if (getValidations() != null) {
            ValidationCollection tempVar3 = validations.clone();
            node.setValidations((ValidationCollection)((tempVar3 instanceof ValidationCollection) ? tempVar3 : null));
        }
        if (getBizActions() != null) {
            BizActionCollection tempVar4 = bizActions.clone();
            node.setBizActions((BizActionCollection)((tempVar4 instanceof BizActionCollection) ? tempVar4 : null));
        }
        return node;
    }

    /**
     * 创建属性
     *
     * @return
     */
    @Override
    protected GspBizEntityElement createElement() {
        return new GspBizEntityElement();
    }

    // 依赖实体
    public final void mergeWithDependentObject(GspBizEntityObject dependentObject, boolean isInit) {
        if (!getIsRef()) {
            return;
        }
        // 基本信息
        mergeObjectBaseInfo(dependentObject, isInit);

        // 字段操作
        mergeContainElements(dependentObject);
        mergeContainAction(dependentObject);
        mergeContainDeterminations(dependentObject);
        mergeContainValidation(dependentObject);

        // 子对象
        mergeChildObjects(dependentObject, isInit);
    }

    private void mergeObjectBaseInfo(GspBizEntityObject dependentObject, boolean isInit) {
        // 当且仅当首次dbe带出时，带出对象的编号名称；后续不覆盖
        if (isInit) {
            setCode(dependentObject.getCode());
            setName(dependentObject.getName());
        }

        setOrderbyCondition(dependentObject.getOrderbyCondition());
        setFilterCondition(dependentObject.getFilterCondition());
        setIsReadOnly(dependentObject.getIsReadOnly());
        setObjectType(dependentObject.getObjectType());
        setIsVirtual(dependentObject.getIsVirtual());
        setBelongModelID(dependentObject.getBelongModelID());

        // 处理ID字段
        IGspCommonElement idElement = getContainElements().getItem(getColumnGenerateID().getElementID());
        getContainElements().removeItem(idElement);

        setColumnGenerateID(dependentObject.getColumnGenerateID());
        setContainConstraints(dependentObject.getContainConstraints());
        // HirarchyInfo = dependentObject.HirarchyInfo;
        for (GspAssociationKey key : dependentObject.getKeys()) {
            getKeys().add(((GspAssociationKey)((key instanceof GspAssociationKey) ? key : null)).clone());
        }
    }

    private void mergeContainElements(GspBizEntityObject dependentObject) {
        if (getContainElements() == null) {
            setContainElements(new GspElementCollection(this));
        }

        GspCommonAssociation parentAsso = null;
        if (getContainElements().size() > 0) {
            parentAsso = (GspCommonAssociation)getContainElements().get(0).getParentAssociation();
        }
        GspElementCollection elements = getContainElements().clone(this, parentAsso);
        GspElementCollection dbeElements = dependentObject.getContainElements();

        // 清空
        getContainElements().clear();

        // 添加当前be的字段,若为dbe字段，则删除重加所属对象改为当前对象
        for (IGspCommonField e : elements) {
            GspBizEntityElement ele = (GspBizEntityElement)e;
            if (ele.getIsRef()) {
                GspBizEntityElement dependentEle = (GspBizEntityElement)dbeElements.getItem(ele.getID());
                addDbeElement(dependentEle, (IGspCommonElement)ele);
                dbeElements.removeItem(dependentEle);
            } else {
                getContainElements().add(ele);
            }
        }

        // 添加dbe新增的ele
        if (dbeElements == null || dbeElements.size() < 1) {
            return;
        }
        for (IGspCommonField ele : dbeElements) {
            addDbeElement((IGspCommonElement)((ele instanceof IGspCommonElement) ? ele : null), null);
        }
    }

    private void addDbeElement(IGspCommonElement ele, IGspCommonElement orgEle) {
        if (ele == null) {
            throw new RuntimeException(String.format("addDbeElement方法参数ele为空。"));
        }
        if (!(ele instanceof GspBizEntityElement)) {
            throw new RuntimeException("Error");
        }
        GspBizEntityElement dbeEle = (GspBizEntityElement)ele;
        GspBizEntityElement newEle = (GspBizEntityElement)dbeEle.clone(this, dbeEle.getParentAssociation());
        if (!(newEle instanceof GspBizEntityElement)) {
            throw new RuntimeException("Error");
        }

        newEle.setID(dbeEle.getID());
        newEle.setIsRef(true);
        if (newEle.getChildElements() != null) {
            for (IGspCommonField childEle : newEle.getChildElements()) {
                childEle.setIsRef(true);
            }
        }
        if (orgEle != null) {
            newEle.setColumnID(orgEle.getColumnID());
            if (newEle.getChildElements() != null) {
                for (int i = 0; i < newEle.getChildElements().size(); i++) {
                    IGspCommonElement commonEl = (IGspCommonElement)newEle.getChildElements().get(i);
                    if (commonEl == null) {
                        continue;
                    }
                    if (i >= orgEle.getChildElements().size()) {
                        continue;
                    }
                    commonEl.setColumnID(((IGspCommonElement)orgEle.getChildElements().get(i)).getColumnID());
                }
            }
        }

        getContainElements().add(newEle);
    }

    private void mergeContainDeterminations(GspBizEntityObject dependentObject) {
        getDeterminations().mergeDbeOperations(dependentObject.getDeterminations());
    }

    private void mergeContainValidation(GspBizEntityObject dependentObject) {
        getValidations().mergeDbeOperations(dependentObject.getValidations());
    }

    private void mergeContainAction(GspBizEntityObject dependentObject) {
        getBizActions().mergeDbeOperations(dependentObject.getBizActions());
    }

    private void mergeChildObjects(GspBizEntityObject dependentObject, boolean isInit) {
        GspObjectCollection dbeChildObjects = dependentObject.getContainChildObjects().clone(this);
        GspObjectCollection childObjects = getContainChildObjects().clone(this);

        getContainChildObjects().clear();
        // 已有子对象
        if (childObjects != null && childObjects.size() > 0) {
            for (IGspCommonObject childObj : childObjects) {
                GspBizEntityObject childObject = (GspBizEntityObject)childObj;
                if (childObject.getIsRef()) {
                    for (IGspCommonObject dbeChildObj : dbeChildObjects) {
                        if (dbeChildObj.getID().equals(childObject.getID())) {
                            GspBizEntityObject dbeChildObject = (GspBizEntityObject)dbeChildObj;
                            childObject.mergeWithDependentObject(dbeChildObject, isInit);
                            getContainChildObjects().add(childObject);
                            dbeChildObjects.removeItem(dbeChildObject);
                        } else {
                            continue;
                        }
                    }
                } else {
                    getContainChildObjects().add(childObject);
                }
            }
        }

        // 若dbe中包含未对应到当前be的子对象，则新增
        if (dbeChildObjects == null || dbeChildObjects.size() < 1) {
            return;
        }
        for (IGspCommonObject item : dbeChildObjects) {
            GspBizEntityObject tempVar = new GspBizEntityObject();
            tempVar.setID(item.getID());
            tempVar.setIsRef(true);
            GspBizEntityObject newObj = tempVar;
            newObj.mergeWithDependentObject((GspBizEntityObject)((item instanceof GspBizEntityObject) ? item : null), true); // 首次添加，故isInit为true,带出对象编号名称
            getContainChildObjects().add(newObj);
        }
    }



    public final void initMainObject() {
        setObjectType(GspCommonObjectType.MainObject);
        getBizActions().add(new DeleteBEAction());
        getBizActions().add(new ModifyBEAction());
        getBizActions().add(new RetrieveBEAction());
    }

    // 创建BE子节点

    /**
     * 根据BE父节点生成子节点
     *
     * @param childObjCode BE子节点编号
     * @param childObjName BE子节点名称
     */
    // ORIGINAL LINE: public GspBizEntityObject createChildObject(string
    // childObjCode = "childObj", string childObjName = "childObj")
    public final GspBizEntityObject createChildObject(String childObjCode, String childObjName) {
        if (childObjCode.isEmpty()) {
            childObjCode = "childObj";
        }
        if (childObjName.isEmpty()) {
            childObjName = "childObj";
        }
        GspBizEntityObject childObj = initNewBizObject(childObjCode, childObjName);

        // 新增父节点id字段
        GspBizEntityElement parentIDElement = initParentIDElement();
        childObj.getContainElements().add(parentIDElement);

        // 子节点新增与父节点的关联
        GspAssociationKey key = new GspAssociationKey();
        GspBizEntityElement parentIdElement = initParentObjectIDElement();
        key.setTargetElement(parentIdElement.getID());
        key.setTargetElementDisplay(parentIdElement.getName());
        key.setSourceElement(parentIDElement.getID());
        key.setSourceElementDisplay(parentIDElement.getName());
        childObj.getKeys().add(key);
        return childObj;
    }

    private GspBizEntityObject initNewBizObject(String childObjCode, String childObjName) {
        GspBizEntityObject childObj = new GspBizEntityObject();
        GspBizEntityElement idElement = initIDElement();
        childObj.setID(Guid.newGuid().toString());
        childObj.setCode(childObjCode);
        childObj.setName(childObjName);
        GspColumnGenerate newColumnGenerate = new GspColumnGenerate();
        newColumnGenerate.setElementID(idElement.getID());
        newColumnGenerate.setGenerateType("Guid");
        childObj.setColumnGenerateID(newColumnGenerate);
        childObj.getContainElements().add(idElement);
        childObj.setObjectType(GspCommonObjectType.ChildObject);
        return childObj;
    }

    private GspBizEntityElement initIDElement() {
        GspBizEntityElement idElement = new GspBizEntityElement();
        idElement.setID(Guid.newGuid().toString());
        idElement.setCode("ID");
        idElement.setName("ID");
        idElement.setLabelID("ID");
        idElement.setMDataType(GspElementDataType.String);
        idElement.setObjectType(GspElementObjectType.None);
        idElement.setLength(36);
        idElement.setPrecision(0);
        idElement.setIsRequire(true);
        return idElement;
    }

    private GspBizEntityElement initParentObjectIDElement() {
        if (this.getColumnGenerateID() == null || this.getColumnGenerateID().getElementID().isEmpty()) {
            throw new RuntimeException("父节点ColumnGenerateID属性为空");
        }
        Object tempVar = this.getContainElements().getItem(this.getColumnGenerateID().getElementID());
        return (GspBizEntityElement)((tempVar instanceof GspBizEntityElement) ? tempVar : null);
    }

    private GspBizEntityElement initParentIDElement() {
        GspBizEntityElement idElement = new GspBizEntityElement();
        idElement.setID(Guid.newGuid().toString());
        idElement.setCode("ParentID");
        idElement.setName("ParentID");
        idElement.setLabelID("ParentID");
        idElement.setMDataType(GspElementDataType.String);
        idElement.setObjectType(GspElementObjectType.None);
        idElement.setLength(36);
        idElement.setPrecision(0);
        idElement.setIsRequire(true);
        return idElement;
    }




}